package com.efei.jdbc.dynamic.query.service;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.efei.common.exception.ErrorMsgException;
import com.efei.common.pojo.ResponseData;
import com.efei.jdbc.dynamic.query.dao.SysQueryRepository;
import com.efei.jdbc.dynamic.query.element.QueryFilterElement;
import com.efei.jdbc.config.SysQueryConfiguation;
import com.efei.jdbc.dynamic.query.element.QueryElement;
import com.efei.jdbc.dynamic.query.filter.GobalQueryFilter;
import com.efei.jdbc.dynamic.query.filter.LocalQueryFilter;
import com.efei.jdbc.dynamic.query.entity.SysQueryEntity;
import com.efei.jdbc.sql.SqlSelect;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

public class SysQueryService {
    public  static final String QUERY_ID="queryid";
    public  static final String QUERY_BODY="body";
    @Autowired
    private HttpServletRequest request;
//
//	@Autowired
//	private HttpServletResponse response;

    @Autowired
    private SysQueryRepository sysQueryRepository;

    @Autowired
    private List<GobalQueryFilter> listGobalQueryFilter;

    @Autowired
    private List<LocalQueryFilter> listLocalQueryFilter;

    private Map<String,LocalQueryFilter> mapLocalQueryFilter = new LinkedHashMap<String, LocalQueryFilter>();

    @Autowired
    private SysQueryConfiguation queryConfiguation;

    @PostConstruct
    public void init() {

        Collections.sort(listGobalQueryFilter, new Comparator<GobalQueryFilter>() {
            @Override
            public int compare(GobalQueryFilter o1, GobalQueryFilter o2) {
                int v1 = Integer.MAX_VALUE;
                int v2 = Integer.MAX_VALUE;
                Order a1 = o1.getClass().getAnnotation(Order.class);
                Order a2 = o2.getClass().getAnnotation(Order.class);
                if(a1!=null) {
                    v1 = a1.value();
                }
                if(a2!=null) {
                    v2 = a2.value();
                }
                return v1-v2;
            }
        });

        // 如果名字相同会引起覆盖问题
        listLocalQueryFilter.forEach(f->{
            String key = f.getClass().getSimpleName();
            mapLocalQueryFilter.computeIfAbsent(key, k->{
                return f;
            });
        });
    }

    /**
     * 一般前端展示使用
     * 获取数据列信息
     * @param queryid
     * @return
     */
    public ResponseData getColumList(Long queryid) {
        QueryElement qe = getQueryElment(queryid);
        JSONArray cloumJson = qe.getCloumJson();
        JSONArray columns = new JSONArray(); // 给前端的json格式
        cloumJson.forEach(v->{
            JSONObject jo = (JSONObject)v;
            JSONObject t = new JSONObject();
            t.put("title", jo.getString("label"));
            t.put("key", jo.getString("name"));
            columns.add(t);
        });
        return ResponseData.ok(columns);
    }

    /**
     * 查询数据
     * @param queryid
     * @param pageable
     * @param body
     * @return
     */
    public Page<Map<String, Object>> getPageList(Long queryid, Pageable pageable, String body) {

        // 查询配置
        QueryElement qe = getQueryElment(queryid);
        request.setAttribute(QUERY_ID, String.valueOf(queryid));
        request.setAttribute(QUERY_BODY, body);

        // 获取动态SQL
        SqlSelect sql = qe.getDynamicSql();

        // 全局处理器
        for(GobalQueryFilter filter : listGobalQueryFilter) {
            filter.before(sql,null);
        }

        // 局部处理器
        List<QueryFilterElement> filters = qe.getFilters();
        filters.forEach(s->{
            LocalQueryFilter fiter = mapLocalQueryFilter.get(s.getFilterName());
            if(fiter!=null) {
                fiter.before(sql,s.getParameter());
            }
        });
        Page<Map<String, Object>> pd = null;
        if(pageable.isPaged()) {
            //pd = sysQueryRepository.selectPageDataBySQL(sql, pageable);
        } else {
            Pageable pageable2 = PageRequest.of(0, 100000);
            //pd = commonRepository.selectPageDataBySQL(sql, pageable2,null,false);
        }


        // 全局处理器
        for(GobalQueryFilter filter : listGobalQueryFilter) {
            filter.after(pd,null);
        }

        // 局部处理器
        int len = filters.size();
        for(int i=0;i < len;i++) {
            QueryFilterElement f = filters.get(i);
            LocalQueryFilter filter = mapLocalQueryFilter.get(f.getFilterName());
            filter.after(pd, f.getParameter());
        }
        return pd;
    }

    public List<Map<String, Object>> getList(Long queryid,Pageable pageable,String body) {
        Page<Map<String, Object>> data = getPageList(queryid, pageable, body);
        return data.getContent();
    }

    public List<Map<String, Object>> getList(Long queryid,String body) {
        Pageable pageable = Pageable.unpaged();
        Page<Map<String, Object>> data = getPageList(queryid, pageable, body);
        return data.getContent();
    }


    private QueryElement getQueryElment(Long queryid) {
        if(queryid==null) {
            throw new ErrorMsgException("queryid is null");
        }
        // 写入配置文件
        QueryElement qe = queryConfiguation.getQueryElment(String.valueOf(queryid));
        Boolean  reput = BooleanUtils.toBooleanObject(request.getParameter("reput"));
        if(reput==null) {
            reput = Boolean.FALSE;
        }
        if(qe==null || reput) {
            SysQueryEntity se = sysQueryRepository.findById(queryid).get();
            if(se==null) {
                throw new ErrorMsgException("queryid is error");
            }
            qe = queryConfiguation.addQueryElment(String.valueOf(queryid), new QueryElement(se),reput);
        }
        return qe;
    }
}

